﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Mail;
using System.Net.Mime;
using System.IO;
using System.Diagnostics;
using System.Threading;

namespace Send2SMTP
{
    class Program
    {
        public static object lockCount = new object();
        public static int m_sentCount = 0;
        public static int m_randomSeed = -1;

        static void Main(string[] args)
        {
            try
            {
                MailThreadData masterBlob = new MailThreadData();

                char[] standardDelims = new char[] { ';', ',' };
                int numThreads = 5;

                //
                // Process arguments...
                if (args.Length == 0)
                {
                    PrintBanner();
                    Environment.Exit(0);
                }
                else
                {
                    for (int argIndex = 0; argIndex < args.Length; argIndex++)
                    {
                        switch (args[argIndex].ToLower())
                        {
                            case "-copies":
                            case "-cp":
                                masterBlob.copies = Convert.ToInt32(args[++argIndex]);
                                break;

                            case "-from":
                            case "-f":
                                masterBlob.from = new MailAddress(args[++argIndex]);
                                break;

                            case "-?":
                                PrintBanner();
                                Environment.Exit(0);
                                break;

                            case "-to":
                                AddRecipients(masterBlob.toList, args[++argIndex].Split(standardDelims));
                                break;

                            case "-tofile":
                                AddRecipients(masterBlob.toList, File.ReadAllLines(args[++argIndex]));
                                break;

                            case "-cc":
                                AddRecipients(masterBlob.ccList, args[++argIndex].Split(standardDelims));
                                break;

                            case "-ccfile":
                                AddRecipients(masterBlob.ccList, File.ReadAllLines(args[++argIndex]));
                                break;

                            case "-bcc":
                                AddRecipients(masterBlob.bccList, args[++argIndex].Split(standardDelims));
                                break;

                            case "-bccfile":
                                AddRecipients(masterBlob.bccList, File.ReadAllLines(args[++argIndex]));
                                break;

                            case "-host":
                            case "-h":
                                masterBlob.host = args[++argIndex];
                                break;

                            case "-port":
                            case "-p":
                                masterBlob.port = Convert.ToInt32(args[++argIndex]);
                                break;

                            case "-subject":
                            case "-s":
                                masterBlob.subject = args[++argIndex];
                                break;


                            case "-attach":
                            case "-a":
                                string[] attArray = args[++argIndex].Split(standardDelims);
                                foreach (string attachFile in attArray)
                                {
                                    masterBlob.attachmentList.Add(attachFile);
                                }
                                break;
                            case "-attachdir":
                                masterBlob.attachmentList.InsertRange(0, Directory.GetFiles(args[++argIndex], "*", SearchOption.TopDirectoryOnly));
                                break;

                            case "-body":
                            case "-b":
                                masterBlob.body = args[++argIndex];
                                break;

                            case "-bodyfile":
                            case "-bf":
                                masterBlob.body = File.ReadAllText(args[++argIndex]);
                                break;

                            case "-bodyishtml":
                            case "-bhtml":
                                masterBlob.bodyIsHTML = Convert.ToBoolean(args[++argIndex]);
                                break;

                            case "-attachprob":
                            case "-ap":
                                masterBlob.attachProb = Convert.ToDouble(args[++argIndex]) / 100.0;
                                break;

                            case "-randomattachments":
                            case "-ra":
                                masterBlob.minAttachments = Convert.ToInt32(args[++argIndex]);
                                masterBlob.maxAttachments = Convert.ToInt32(args[++argIndex]);
                                break;

                            case "-threads":
                            case "-th":
                                numThreads = Convert.ToInt32(args[++argIndex]);
                                break;

                            case "-seed":
                                m_randomSeed = Convert.ToInt32(args[++argIndex]);
                                break;

                            case "-delay":
                                masterBlob.delay = Convert.ToInt32(args[++argIndex]);
                                break;

                            case "-creds":
                                masterBlob.useDefaultCreds = false;
                                masterBlob.userName = args[++argIndex];
                                masterBlob.password = args[++argIndex];
                                //
                                // Examine next param, does it begin with a '-' ?. If not, assume it's
                                // a domain name
                                if ((argIndex+1<args.Length) && args[argIndex + 1][0] != '-')
                                {
                                    masterBlob.domain = args[++argIndex];
                                }
                                break;

                            case "-ssl":
                                masterBlob.useSSL = true;
                                break;
                        }
                    }
                }

                DateTime startTime = DateTime.Now;

                Thread[] threads = new Thread[numThreads];
                MailThreadData[] threadData = new MailThreadData[numThreads];
                for (int threadIndex = 0; threadIndex < numThreads; threadIndex++)
                {
                    threadData[threadIndex] = masterBlob.DeepCopy();
                    threadData[threadIndex].threadId = threadIndex;
                    MailThread mailThread = new MailThread();
                    threads[threadIndex] = new Thread(mailThread.ThreadEntryPoint);
                    threads[threadIndex].Start(threadData[threadIndex]);
                }

                for (int threadIndex = 0; threadIndex < numThreads; threadIndex++)
                {
                    threads[threadIndex].Join();
                }
                DateTime stopTime = DateTime.Now;
                int totalMessages = 0;
                int messagesWithAttachments = 0;
                System.Console.WriteLine();
                System.Console.WriteLine("-----------------------------------------------------------------------");
                System.Console.WriteLine("Summary");
                System.Console.WriteLine("-----------------------------------------------------------------------");
                System.Console.WriteLine("Time taken (seconds)  :" + (stopTime - startTime).TotalSeconds);
                for (int threadIndex = 0; threadIndex < numThreads; threadIndex++)
                {
                    System.Console.WriteLine("Thread " + (threadIndex + 1) + ": Sent " + threadData[threadIndex].sentMessages);
                    totalMessages += threadData[threadIndex].sentMessages;
                    messagesWithAttachments += threadData[threadIndex].messagesWithAttachments;
                }
                System.Console.WriteLine("Total messages sent   :" + totalMessages.ToString());
                System.Console.WriteLine("  with attachments    :" + messagesWithAttachments.ToString() + " (" + ((int)(((double)messagesWithAttachments / (double)totalMessages) * 100.0)).ToString() + "%)");
            }
            catch (Exception exp)
            {
                System.Console.WriteLine("Send2SMTP caught an exception:" + exp);
            }
        }

        static void AddRecipients(List<MailAddress> addresses,string[] lines)
        {
            char[] delims = new char[] { ';'};
            foreach (string line in lines)
            {
                string[] elements = line.Split(delims);
                switch (elements.Length)
                {
                    case 1:
                        addresses.Add(new MailAddress(elements[0]));
                        break;
                    case 2:
                        addresses.Add(new MailAddress(elements[0], elements[1]));
                        break;
                }
            }
        }

        static void PrintBanner()
        {
            System.Console.WriteLine("http://Send2SMTP.codeplex.com");
            System.Console.WriteLine("Usage: Send2SMTP [options] -host <hostname> -from <from> -to <to> ");
            System.Console.WriteLine("Where options are -");
            System.Console.WriteLine(" -host\t\tSMTP host address");
            System.Console.WriteLine(" -port\t\tPort (default 25)");
            System.Console.WriteLine(" -ssl\t\tUse SSL/TLS");
            System.Console.WriteLine(" -creds\t\tCredentials (user pw [domain])");
            System.Console.WriteLine(" -from\t\t'From' address e.g pj@mydomain.com");
            System.Console.WriteLine(" -to\t\t'To' address e.g you@yourdomain.com");
            System.Console.WriteLine(" -tofile\t'To' recipient list file");
            System.Console.WriteLine(" -copies\tNumber of messages to send (default 1)");
            System.Console.WriteLine(" -cc\t\t'CC' address");
            System.Console.WriteLine(" -ccfile\t'CC' recipient list file");
            System.Console.WriteLine(" -bcc\t\t'BCC' address");
            System.Console.WriteLine(" -bccfile\t'BCC' recipient list file");
            System.Console.WriteLine(" -subject\t'Subject' field");
            System.Console.WriteLine(" -attach\tAttachment file name (can appear multiple times)");
            System.Console.WriteLine(" -attachdir\tDirectory containing pool of attachments");
            System.Console.WriteLine(" -body\t\t'Body' field");
            System.Console.WriteLine(" -bodyfile\tFile to load body in");
            System.Console.WriteLine(" -bodyishtml\tIs body HTML (default is false)");
            System.Console.WriteLine(" -attachprob\tProbability of an attachment (0..100). Default is 0 (never)");
            System.Console.WriteLine(" -randomattachments min max\t Range of random attachments (default is 1 and 3 respectively)");
            System.Console.WriteLine(" -seed\t\tRandom number seed (default -1 = current tick)");
            System.Console.WriteLine(" -threads\tNumber of connection threads (default 5)");
            System.Console.WriteLine(" -delay\t\tDelay (in ms) between each mail sent");
        }

        void WriteFormattedLine(string line, int width)
        {

        }
    }
}
